home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
os2
/
gtak258.zip
/
RMT
/
rmt_tape.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-12
|
9KB
|
470 lines
/*****************************************************************************
* $Id: rmt_tape.c,v 1.20 1996/06/12 16:44:38 ak Exp $
*****************************************************************************
* $Log: rmt_tape.c,v $
* Revision 1.20 1996/06/12 16:44:38 ak
* Must not flush in rmtseek(tell).
*
* Revision 1.19 1996/06/03 01:52:42 ak
* Use QFA to rewind to beginning of volume.
* Fixed seek mode=1 and relative blocks.
*
* Revision 1.18 1996/06/03 00:33:48 ak
* Fix seek(,,0).
*
* Revision 1.17 1995/07/20 22:58:48 ak
* VACPP 3.0.
*
* Revision 1.16 1994/11/11 22:16:05 ak
* *** empty log message ***
*
* Revision 1.15 1994/08/12 10:26:34 ak
* .
*
* Revision 1.14 1994/08/12 10:15:43 ak
* Handle RecoveredData sense codes produced by Cipher devices.
*
* Revision 1.13 1994/08/03 10:27:40 ak
* Added option for retry, as undocumented hidden magic.
*
* Revision 1.12 1994/07/06 21:19:34 ak
* Bugfix.
*
* Revision 1.11 1994/06/02 13:40:31 ak
* Stop reading when a filemark is encountered.
*
* Revision 1.10 1994/02/16 15:29:20 edvkai
* Dummy checkin for CVS 1.3 crlf.
*
* Revision 1.9 1993/12/14 21:55:34 ak
* Bugfix. Partition number must be -1 (no change).
*
* Revision 1.8 1993/11/29 16:59:25 edvkai
* *** empty log message ***
*
* Revision 1.7 1993/11/26 21:59:37 edvkai
* Added "rewind" for relative multi-volume QFA.
*
* Revision 1.6 1993/11/25 18:54:01 edvkai
* Removed DLL import by number.
* Changed return codes to avoid ambiguities.
* Changed lseek into seek, parameter changes.
*
* Revision 1.3 1993/04/26 14:49:29 AK
* AIX.
*
* Revision 1.2 1993/02/10 13:41:56 AK
* Check for write-protected tapes.
* Flag '+' for append to EOT.
*
* Revision 1.1.1.1 1993/02/08 21:32:17 AK
* TAR device interface DLLs.
*
* Revision 1.1 1993/02/08 21:32:15 AK
* Initial revision
*
*****************************************************************************/
static char *rcsid = "$Id: rmt_tape.c,v 1.20 1996/06/12 16:44:38 ak Exp $";
/*
* rmt_tape.c
*
* Tape interface for GNU tar.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include "scsi.h"
#include "tape.h"
#include "errtab.h"
#ifndef __IBMC__
# define _System
#endif
extern FILE *msg_file;
static int tape_no = 0;
static long tapeblock = -1;
static long last_error = 0;
static int retry;
static int wrflag;
static int filemark;
static long initial;
#define Retries 5
#define Trace 0
int _System
rmt_open(char *name, int mode, int prot)
{
long r;
int eot = 0;
#if Trace
printf("rmt_open(\"%s\", 0x%X, 0%o)\n", name, mode, prot);
#endif
filemark = wrflag = retry = 0;
if (*name == '+') {
++name;
eot = 1;
}
if (*name == '!') {
++name;
retry = 1;
}
if ((r = tape_open(name)) != 0) {
last_error = r;
return -2;
}
tape_ready(); /* skip "Cartridge Changed" */
r = tape_ready();
if (!r)
r = tape_get_blocksize(&tapeblock);
if (r) {
last_error = r;
return -2;
}
if (++tape_no == 1)
switch (mode & 3) {
case O_RDWR:
/* remember current position */
tape_tell(&initial, NULL);
case O_WRONLY:
r = tape_writable();
if (r) {
last_error = r;
return -2;
}
if (eot)
tape_space(TapeSpace_LogEndOfMedia, 0L, NULL);
}
else
tape_rewind(0);
return 0;
}
long
repeat(long _System fcn (void _far *, long, long *), long *actual, long r,
char *p, unsigned len)
{
int n;
long actual2 = *actual, r2 = r;
if (actual2 == TapeUndefLength) {
printf(">>> RETRY NOT POSSIBLE\n");
return r;
}
for (n = 1; n <= Retries; ++n) {
p += actual2;
len -= actual2;
if (len == 0)
return *actual;
printf(">>> RETRY #%d: %s\n", n, tape_status(r2));
r2 = fcn(p, len, &actual2);
if (actual2 == TapeUndefLength)
return r2;
*actual += actual2;
}
return r;
}
int _System
rmt_read(int fd, void *p, unsigned len)
{
long actual = TapeUndefLength, r = 0;
#if Trace
printf("rmt_read(, %p, %u)\n", p, len);
#endif
if (filemark)
return 0;
r = tape_read(p, len, &actual);
if (ErrorClass(r) == ErrclDeviceError
&& ErrorType(r) == ErrtySenseByte
&& (ErrorCode(r) & 0x0F) == RecoveredData) {
/* Cipher */
if (actual == TapeUndefLength)
actual = len;
if (r & 0xF0)
r &= ~0x0F;
else
r = 0;
}
if (r && retry)
r = repeat(tape_read, &actual, r, p, len);
if (actual == TapeUndefLength)
actual = 0;
if (r) {
last_error = r;
if (ErrorClass(r) == ErrclDeviceError
&& ErrorType(r) == ErrtySenseByte) {
if (r & FM)
filemark = 1;
if (ErrorCode(r) == MediaOverflow)
return -3;
if (ErrorCode(r) == FM+NoSense)
return actual;
}
if (actual == 0)
return -2;
}
return actual;
}
int _System
rmt_write(int fd, void *p, unsigned len)
{
long actual = TapeUndefLength, r = 0;
#if Trace
printf("rmt_write(, %p, %u)\n", p, len);
#endif
wrflag = 1;
r = tape_write(p, len, &actual);
if (ErrorClass(r) == ErrclDeviceError
&& ErrorType(r) == ErrtySenseByte
&& (ErrorCode(r) & 0x0F) == RecoveredData) {
/* Cipher */
if (actual == TapeUndefLength)
actual = len;
if (r & 0xF0)
r &= ~0x0F;
else
r = 0;
}
if (r && retry)
r = repeat(tape_write, &actual, r, p, len);
if (actual == TapeUndefLength)
actual = 0;
if (r) {
last_error = r;
if (r == ErrclDeviceError+ErrtySenseByte+MediaOverflow)
return -3;
if (actual == 0)
return -2;
}
return actual;
}
static long
flush(void)
{
if (wrflag) {
long r;
wrflag = 0;
r = tape_filemark(0, 1L, NULL);
if (r) {
last_error = r;
return -2;
}
filemark = 1;
}
return 0;
}
long _System
rmt_seek(int fd, long block, long blocksz, int mode)
{
/* used: 0/1/2 -> standard lseek, return code 0
3 -> physical block, return code 0
4 -> return current phys block
5 -> rewind tape
logical block is TAR block, not tape block
*/
long r, actual;
#if Trace
printf("rmt_seek(, %ld, %ld, %d)\n", block, blocksz, mode);
#endif
switch (mode) {
case 5:
if (flush())
return -2;
filemark = 0;
r = tape_rewind(0);
if (r) {
last_error = r;
return -2;
}
return 0;
case 4:
r = tape_tell(&actual, NULL);
if (r) {
last_error = r;
return -2;
}
return actual;
case 3:
if (flush())
return -2;
filemark = 0;
/* physical block, direct seek required */
r = tape_seek(0, block, -1);
if (r) {
last_error = r;
return -2;
}
return 0;
case 2:
if (flush())
return -2;
if (!filemark)
r = tape_space(TapeSpace_Filemarks, 1L, &actual);
filemark = 0;
break;
case 1:
if (flush())
return -2;
if (filemark) {
/* beyond filemark at end of volume, skip reverse */
r = tape_space(TapeSpace_Filemarks, -1L, &actual);
if (r && actual != -1)
break;
filemark = 0;
} else
r = 0;
break;
case 0:
if (flush())
return -2;
if (initial != TapeUndefLength) {
/* QFA position of beginning of volume available */
r = tape_seek(0, initial, -1);
filemark = 0;
} else {
/* no QFA available, use filemark skips */
if (filemark) {
/* beyond filemark at end of volume, skip reverse */
r = tape_space(TapeSpace_Filemarks, -1L, &actual);
if (r && actual != -1)
break;
filemark = 0;
}
/* find the filemark at beginning of volume */
r = tape_space(TapeSpace_Filemarks, -1L, &actual);
if (actual == -1) {
/* really found a filemark, skip forward */
r = tape_space(TapeSpace_Filemarks, 1L, &actual);
} else if (r == ErrclDeviceError+ErrtySenseByte+EOM+NoSense) {
/* we hit BOT instead, accept */
r = 0;
}
}
break;
default:
return -4;
}
if (block && !r) {
if (tapeblock)
block *= blocksz / tapeblock;
r = tape_space(TapeSpace_Blocks, block, &actual);
if (r == ErrclDeviceError+ErrtySenseByte+EOM+NoSense
|| r == ErrclDeviceError+ErrtySenseByte+FM+NoSense)
r = 0;
}
#if Trace
if (tape_tell(&actual, NULL) == 0)
printf(" result position is %ld\n", actual);
#endif
if (!r)
return 0;
last_error = r;
return -2;
}
int _System
rmt_close(int fd)
{
long r = 0;
#if Trace
printf("rmt_close(,)\n");
#endif
if (flush()) {
r = last_error;
tape_close();
} else
r = tape_close();
if (!r)
return 0;
last_error = r;
return -2;
}
int _System
rmt_ioctl(int fd, int code, void *arg)
{
return -4;
}
int _System
rmt_block(int fd)
{
return tapeblock;
}
long _System
rmt_error(void)
{
return last_error;
}
char * _System
rmt_status(long rcode)
{
return tape_status(rcode);
}
#if defined(__EMX__)
unsigned long
_DLL_InitTerm(unsigned long mod_handle, unsigned long flag)
{
if (!flag) {
_CRT_init();
} else {
_CRT_term();
}
return 1;
}
#elif defined(unix)
int
rmt_startup(void)
{
tape_no = 0;
tapeblock = 512;
last_error;
return 0;
}
#endif